package com.sxkawzp.area.service;

import com.sxkawzp.area.dao.AreaDao;
import com.sxkawzp.area.domain.AdministrativeDivision;
import com.sxkawzp.area.exception.AreaException;
import com.sxkawzp.area.request.AdministrativeDivisionForm;
import com.sxkawzp.area.vo.TreeAdministrativeDivisionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;

/**
 * @author suxingkang
 * @version 1.0
 * @since 2025/1/21 9:05
 */
@Slf4j
@Service
public class AreaService {

    @Resource
    private AreaDao areaDao;


    public AdministrativeDivision findByCodeArea(String areaCode) {
        return areaDao.selectByAreaCode(areaCode);
    }

    public TreeAdministrativeDivisionVO findAllAreaTree(String areaCode) {
        if (!StringUtils.hasText(areaCode)) {
            return null;
        }
        AdministrativeDivision administrativeDivision = areaDao.selectByAreaCode(areaCode);
        if (Objects.isNull(administrativeDivision)) {
            return null;
        }
        TreeAdministrativeDivisionVO root = new TreeAdministrativeDivisionVO();
        BeanUtils.copyProperties(administrativeDivision, root);

        List<AdministrativeDivision> administrativeDivisionList = areaDao.selectChildByAreaCode(administrativeDivision.getAncestor(), administrativeDivision.getLft(), administrativeDivision.getLft());
        Map<Integer, List<TreeAdministrativeDivisionVO>> pidAndAreaInfoMap = administrativeDivisionList.stream()
                .map(e -> {
                    TreeAdministrativeDivisionVO treeAdministrativeDivisionVO = new TreeAdministrativeDivisionVO();
                    BeanUtils.copyProperties(e, treeAdministrativeDivisionVO);
                    return treeAdministrativeDivisionVO;
                })
                .collect(Collectors.groupingBy(e -> e.getPid()));

        Queue<TreeAdministrativeDivisionVO> divisionQueue = new LinkedBlockingQueue<>();
        divisionQueue.add(root);

        while (!divisionQueue.isEmpty()) {
            TreeAdministrativeDivisionVO poll = divisionQueue.poll();
            if (Objects.isNull(poll)) {
                continue;
            }
            List<TreeAdministrativeDivisionVO> childList = pidAndAreaInfoMap.get(poll.getId());
            if (!CollectionUtils.isEmpty(childList)) {
                poll.setChildAdministrativeDivisions(childList);
                divisionQueue.addAll(childList);
            }
        }
        return root;
    }

    public Boolean insertArea(AdministrativeDivisionForm request) {
        int pid = request.getPid();

        int lft;
        int rgt;
        int lev;
        int ancestor = 0;

        if (pid != 0) {
            AdministrativeDivision parent = areaDao.selectById(pid);
            lft = parent.getLft();
            rgt = parent.getRgt();
            lev = parent.getLev();
            ancestor = parent.getAncestor();

            int updateCount = areaDao.updateLft(ancestor, lft);
            if (updateCount < 1) {
                throw new AreaException("更新左范围失败");
            }
            updateCount = areaDao.updateRgt(ancestor, lft);
            if (updateCount < 1) {
                throw new AreaException("更新右范围失败");
            }

            int curLft = lft + 1;
            int curRgt = curLft + 1;
            AdministrativeDivision administrativeDivision = new AdministrativeDivision();
            administrativeDivision.setAreaName(request.getAreaName());
            administrativeDivision.setAreaCode(request.getAreaCode());
            administrativeDivision.setPid(request.getPid());
            administrativeDivision.setLft(curLft);
            administrativeDivision.setRgt(curRgt);
            administrativeDivision.setLev(lev + 1);
            administrativeDivision.setAncestor(ancestor);
            administrativeDivision.setSort(request.getSort());
            administrativeDivision.setAreaRange(request.getAreaRange());
            areaDao.insert(administrativeDivision);
        } else {
            lft = 1;
            rgt = 2;
            lev = 1;
            AdministrativeDivision administrativeDivision = new AdministrativeDivision();
            administrativeDivision.setAreaName(request.getAreaName());
            administrativeDivision.setAreaCode(request.getAreaCode());
            administrativeDivision.setPid(request.getPid());
            administrativeDivision.setLft(lft);
            administrativeDivision.setRgt(rgt);
            administrativeDivision.setLev(lev);
            administrativeDivision.setAreaRange(request.getAreaRange());
            administrativeDivision.setAncestor(ancestor);
            administrativeDivision.setSort(request.getSort());
            // 此处不仅要保存要添加的区划，还要将自身的ID 保存到祖先ID中
            areaDao.insert(administrativeDivision);
            administrativeDivision.setAncestor(administrativeDivision.getId());
            areaDao.update(administrativeDivision);
        }


        return null;
    }

    public Boolean updateArea(AdministrativeDivisionForm request) {

        int id = request.getId();
        AdministrativeDivision administrativeDivision = areaDao.selectById(id);
        if (Objects.isNull(administrativeDivision)) {
            return Boolean.FALSE;
        }

        administrativeDivision.setAreaName(request.getAreaName());
        administrativeDivision.setAreaCode(request.getAreaCode());
        administrativeDivision.setAreaRange(request.getAreaRange());
        administrativeDivision.setSort(request.getSort());
        areaDao.update(administrativeDivision);
        return Boolean.TRUE;
    }

    public List<AdministrativeDivision> queryAllPathByAreaCode(String areaCode) {
        if (!StringUtils.hasText(areaCode)) {
            return Collections.emptyList();
        }
        AdministrativeDivision administrativeDivision = areaDao.selectByAreaCode(areaCode);
        if (Objects.isNull(administrativeDivision)) {
            return Collections.emptyList();
        }
        List<AdministrativeDivision> administrativeDivisionList = areaDao.selectByAncestorAndLftAndRgt(administrativeDivision.getAncestor(), administrativeDivision.getLft(), administrativeDivision.getRgt());
        if (!CollectionUtils.isEmpty(administrativeDivisionList)) {
            administrativeDivisionList.sort(Comparator.comparing(AdministrativeDivision::getLev));
        }
        return administrativeDivisionList;
    }
}
